using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.PageFlow;
using System.Globalization;
using Microsoft.Practices.PageFlow.Utils;
using System.Runtime.Serialization;
using WCSFContrib.PageFlow.Xml.Properties;
using System.Security.Permissions;

namespace WCSFContrib.PageFlow.Xml
{
    [Serializable]
    public sealed class XmlPageFlowInstance : ISerializable
    {
        private Guid _instanceId;
        string _currentView;
        PageFlowStatus _status = PageFlowStatus.NotStarted;
        private Type _pageFlowType;
        private XmlPageFlowState _userData;
        private XmlPageFlowRuntime _runtime;

        public XmlPageFlowInstance(Guid instanceId, Type pageFlowType, XmlPageFlowRuntime runtime)
        {
            if (instanceId == Guid.Empty)
                throw new ArgumentException(Resources.IdCannotBeEmpty);

            Guard.ArgumentNotNull(pageFlowType, "pageFlowType");
            Guard.ArgumentNotNull(runtime, "runtime");

            _instanceId = instanceId;
            _pageFlowType = pageFlowType;
            _userData = new XmlPageFlowState();
            _userData.ItemAdded += new EventHandler<EventArgs>(OnItemAdded);
            _runtime = runtime;
        }

        public Guid InstanceId
        {
            get { return _instanceId; }
            set { _instanceId = value; }
        }

        public string CurrentView
        {
            get { return _currentView; }
            set { _currentView = value; }
        }

        public PageFlowStatus Status
        {
            get { return _status; }
        }

        public Type PageFlowType
        {
            get { return _pageFlowType; }
            set { _pageFlowType = value; }
        }

        public XmlPageFlowState UserData
        {
            get { return _userData; }
            set { _userData = value; }
        }

        public XmlPageFlowRuntime Runtime
        {
            get { return _runtime; }
            set { _runtime = value; }
        }

        public void Abort()
        {
            if (_status != PageFlowStatus.Running && _status != PageFlowStatus.Suspended)
                throw new PageFlowException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidStatusChange, this.InstanceId));

            _status = PageFlowStatus.Terminated;
            Runtime.Terminate(this);
        }

        public void Complete()
        {
            if (_status != PageFlowStatus.Running)
                throw new PageFlowException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidStatusChange, this.InstanceId));

            _status = PageFlowStatus.Terminated;
            Runtime.Terminate(this);
        }

        public void Start()
        {
            if (_status != PageFlowStatus.NotStarted)
                throw new PageFlowException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidStatusChange, this.InstanceId));

            _status = PageFlowStatus.Running;
        }

        public void Suspend()
        {
            if (_status != PageFlowStatus.Running)
                throw new PageFlowException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidStatusChange, this.InstanceId));

            _status = PageFlowStatus.Suspended;
        }

        public void Resume()
        {
            if (_status != PageFlowStatus.Suspended)
                throw new PageFlowException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidStatusChange, this.InstanceId));

            _status = PageFlowStatus.Running;
        }


        #region ISerializable Members

        private const string IdKey = "Id";
        private const string CurrentViewKey = "CurrentView";
        private const string StatusKey = "Status";
        private const string TypeKey = "Type";
        private const string UserDataKey = "UserData";

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info != null)
            {
                info.AddValue(IdKey, _instanceId);
                info.AddValue(CurrentViewKey, _currentView);
                info.AddValue(StatusKey, (int)_status);
                info.AddValue(TypeKey, _pageFlowType);
                info.AddValue(UserDataKey, _userData);
            }
        }

        private XmlPageFlowInstance(SerializationInfo info, StreamingContext context)
        {
            _instanceId = (Guid)info.GetValue(IdKey, typeof(Guid));
            _currentView = info.GetString(CurrentViewKey);
            _status = (PageFlowStatus)info.GetInt32(StatusKey);
            _pageFlowType = (Type)info.GetValue(TypeKey, typeof(Type));
            _userData = (XmlPageFlowState)info.GetValue(UserDataKey, typeof(XmlPageFlowState));
            _userData.ItemAdded += new EventHandler<EventArgs>(OnItemAdded);
        }

        #endregion


        public void Persist()
        {
            Runtime.Persist(this);
        }

        private void OnItemAdded(object sender, EventArgs e)
        {
            Persist();
        }
    }
}
